package com.moon.game.server;

import java.net.InetSocketAddress;
import java.util.Map;
import java.util.concurrent.Executors;

import org.apache.log4j.Logger;
import org.dom4j.Element;
import org.jboss.netty.bootstrap.ConnectionlessBootstrap;
import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.FixedReceiveBufferSizePredictorFactory;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.channel.socket.DatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioDatagramChannelFactory;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.codec.serialization.ObjectDecoder;
import org.jboss.netty.handler.codec.serialization.ObjectEncoder;

import com.moon.game.cache.Memcached;
import com.moon.game.config.GlobalConfig;
import com.moon.game.constants.Constants;
import com.moon.game.constants.GlobalConstants;
import com.moon.game.exception.GException;
import com.moon.game.manager.AnimalChildMG;
import com.moon.game.manager.AnimalMG;
import com.moon.game.manager.DB2Proxy;
import com.moon.game.manager.FeteMG;
import com.moon.game.manager.GiftMG;
import com.moon.game.manager.ItemMG;
import com.moon.game.manager.LevelExpMG;
import com.moon.game.manager.MainLandMG;
import com.moon.game.manager.MissionMG;
import com.moon.game.manager.MonsterMG;
import com.moon.game.manager.NPCMG;
import com.moon.game.manager.NoticeMG;
import com.moon.game.profile.ProfileConfig;
import com.moon.game.resource.model.MainLand;
import com.moon.game.service.ChatTask;
import com.moon.game.service.CleanTask;
import com.moon.game.service.MainLandService;
import com.moon.game.util.CommandSet;
import com.moon.game.util.SqlMapConfigData;

public class AppServer {

	public static int serverId;
	private static final Logger log = Logger.getLogger(AppServer.class);
	private static final String CONFIG_FILE = "config.xml";
	private static final String PROFILE_CONFIG_FILE = "mongo_config.xml";
	private static void initProfileConfig() throws GException {
		try {
			ProfileConfig.init(PROFILE_CONFIG_FILE);
		} catch (Exception e) {
			log.error("配置文件加载失败" + e.getMessage(),e);
			throw new GException(e);
		}
	}

	// 初始化配置信息
	private static void initConfig() throws Exception {
		GlobalConfig.init(CONFIG_FILE);
	}

	/**
	 * 启动httpServer
	 */
	private static void startGramServer(){
		DatagramChannelFactory factory = new NioDatagramChannelFactory(Executors.newCachedThreadPool());
		ConnectionlessBootstrap bootstrap = new ConnectionlessBootstrap(factory);
		bootstrap.setPipelineFactory(new DataBufPipelineFactory());
		bootstrap.setOption(GlobalConstants.NETTY_RECEIVE_BUFFER_SIZE_PREDICTOR_FACTORY, new FixedReceiveBufferSizePredictorFactory(GlobalConstants.DATA_SERVER_REC_MAX));
		Element element = GlobalConfig.getAppServer(serverId);
		String host = element.attributeValue("host");
		int port = Integer.parseInt(element.attributeValue("http_port"));
		bootstrap.bind(new InetSocketAddress(host, port));
		log.debug("start HttpServer id:" + serverId + ",host:" + host + ",port:" + port);
	}
	
	/**
	 * 启动AdminServer
	 */
	private static void startAdminServer() {
		ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
		bootstrap.setPipelineFactory(new AdminServerPipelineFactory(new AdminServerHandler()));
		Element element = GlobalConfig.getAppServer(serverId);
		String host = element.attributeValue("host");
		int port = Integer.parseInt(element.attributeValue("admin_port"));
		bootstrap.bind(new InetSocketAddress(host, port));
		log.debug("start Admin Server,host:" + host + ",port:" + port);
	}

	private static class DataBufPipelineFactory implements ChannelPipelineFactory {
		public ChannelPipeline getPipeline() throws Exception {
			// Create a default pipeline implementation.
			ChannelPipeline pipeline = Channels.pipeline();
			pipeline.addLast("decoder", new ObjectDecoder());
			pipeline.addLast("encoder", new ObjectEncoder());
			pipeline.addLast("handler", new DataGramHandler());
			return pipeline;
		}
	}
	
	private static class AdminServerPipelineFactory implements
	ChannelPipelineFactory {
		private SimpleChannelUpstreamHandler handler = null;
		
		public AdminServerPipelineFactory(SimpleChannelUpstreamHandler handler) {
			this.handler = handler;
		}
		
		public ChannelPipeline getPipeline() throws Exception {
			ChannelPipeline pipeline = Channels.pipeline();
			pipeline.addLast("decoder", new HttpRequestDecoder());
			pipeline.addLast("encoder", new HttpResponseEncoder());
			pipeline.addLast("handler", handler);
			return pipeline;
		}
	}
	
	/**
	 * 启动服务
	 */
	private static void startServers() {
		log.debug("start server...");
		startAdminServer();
		log.debug("start server succ！");
		log.debug("start httpServer start");
		startGramServer();
		log.debug("start httpServer succ！");
	}
	
	/**
	 * 启动定时任务
	 */
	private static void initTask() {
		
		log.debug("start chat task start...");
		ChatTask.insc.init();
		log.debug("start chat task succ...");
		
		log.debug("start clear task start...");
		CleanTask.insc.init();
		log.debug("start clear task succ...");
	}
	
	/**
	 * 加载资源前期准备以及资源的加载
	 * @throws GException 
	 * 
	 */
	@SuppressWarnings("static-access")
	private static void initResource() throws GException {
		try {
			GlobalConfig.generateResConfig();
		} catch (Exception e) {
			e.printStackTrace();
		}
		SqlMapConfigData.init();
		
		//加载怪物
		MonsterMG.instance.init();
		//加载NPC
		NPCMG.instance.init();
		//加载大陆
		MainLandMG.instance.init();
		//加载道具
		ItemMG.instance.init();
		//加载大陆到大陆服务
		for (Map.Entry<Integer, MainLand> land : MainLandMG.instance.getMainLandMap().entrySet()) { 
			MainLandService.init(land.getKey());
		}
		//加载珍兽
		AnimalMG.instance.init();
		//加载珍兽孵化资源
		AnimalChildMG.instance.init();
		//加载此等级升级需要的经验配置
		LevelExpMG.instance.init();
		//公告加载
		NoticeMG.instance.init();
		//加载任务
		MissionMG.instance.init();
		//祭祀配置加载
		FeteMG.instance.init();
		//礼包资源加载
		GiftMG.instance.init();
	}
	
	public static void main(String[] args) {
		long start = System.currentTimeMillis();
		if (args.length < 1) {
			log.error("please set server id!");
			System.exit(0);
		}
		try {
			serverId = Integer.parseInt(args[0]);
			log.debug("start appserver： " + serverId);
			
			// 初始化配置
			log.debug("init config start...");
			initConfig();
			log.debug("init config end...");
			
			// 初始化memcached
			log.debug("start memcached start...");
			Memcached.initPool(GlobalConstants.POOL_NAME_SYS, Constants.APP_MEMCACH_CONNECT_SIZE);
			Memcached.initPool(GlobalConstants.POOL_NAME_CHAT, Constants.APP_MEMCACH_CONNECT_SIZE);
			log.debug("start memcached end...");
			
			// 加载资源
			log.debug("init resource start...");
			initResource();
			log.debug("init resource end...");
			
			log.debug("init proxy resource end...");
			DB2Proxy.init();
			log.debug("init proxy resource end...");
			
			// 启动Server
			log.debug("start servers start...");
			startServers();
			log.debug("start servers end...");
			
			// 加载配置文件
			log.debug("start config start...");
			CommandSet.init();
			CommandSet.inst.loadCommand();
			log.debug("start config end...");
			
			//启动逻辑线程
			log.debug("start logic start...");
			for (int i = 0; i < 5; i++) {
				LogicThread lt = new LogicThread();
				lt.start();
			}
			log.debug("start logic end...");
			
			// 加载profile配置
			log.debug("init profileconfig start...");
			initProfileConfig();
			log.debug("init profileconfig end...");
			
			// 重置线程
			log.debug("start reset thread start...");
			ResetThread.init();
			ResetThread.inst.start();
			log.debug("start reset thread end...");
			
			initTask();
		} catch (Exception e) {
			log.error("App server start error.", e);
			System.exit(0);
		}
		long end = System.currentTimeMillis();
		log.debug("start appserver succ ,use:" + (end - start) + "ms");
	}
}
